var ImageManipulator = Class.$extend({
    __init__: function (width, height) {
        this.image = new Image();
        this.imageData = undefined;
        this.divWidth = width;
        this.divHeight = height;
        this.filename = "image";
        var scaledImageSize = {};
        var that = this;
        this.rActive = true;
        this.gActive = true;
        this.bActive = true;
        this.mode = "rgb";
        this.image.onload = function () {
            that.scaledImageSize = getScaledImageSize(that.image.width, that.image.height, that.divWidth, that.divHeight);
            that.canvas.width = that.image.width;
            that.canvas.height = that.image.height;
            that.canvas.getContext('2d').drawImage(that.image, 0, 0);
            that.imageData = that.canvas.getContext('2d').getImageData(0, 0, that.canvas.width, that.canvas.height);
            that.canvas.width = that.canvas.width;
            that.canvas.getContext('2d').drawImage(that.image, 0, 0, that.scaledImageSize.width, that.scaledImageSize.height);
            that.imageLoaded();
        };
        this.canvas = document.createElement('canvas');
    },

    setImage: function (src) {
        this.image.src = src;
    },

    getCanvas: function () {
        return this.canvas;
    },

    multiplyRGBValues: function (r, g, b) {
        var ctx = this.canvas.getContext('2d');
        var imageData = copyImageData(ctx, this.imageData);
        var data = imageData.data;

        for (var i = 0; i < data.length; i += 4) {
            data[i] *= r;
            data[i + 1] *= g;
            data[i + 2] *= b;
        }
        if (this.mode === "gray") {
            this.applyGrayScale(data);
        }

        imageData.data = data;
        ctx.putImageData(imageData, 0, 0);
    },

    transformImage: function (formula) {
        if (this.rActive === false) {
            formula += "\nR = 0;"
        }
        if (this.gActive === false) {
            formula += "\nG = 0;"
        }
        if (this.bActive === false) {
            formula += "\nB = 0;"
        }

        var formulaEquations = formula.split(";");
        var ctx = this.canvas.getContext('2d');
        var imageData = copyImageData(ctx, this.imageData);
        var data = imageData.data;

        var scope = {
            R: 0,
            G: 0,
            B: 0
        };

        for (var j = 0; j < formulaEquations.length; j++) {
            var eq = formulaEquations[j].split("=");
            var id = -1; // 0 - r, 1 - g, 2 - b
            eq[0] = eq[0].trim(); //remove white spaces
            switch (eq[0]) {
                case 'R':
                    id = 0;
                    break;
                case 'G':
                    id = 1;
                    break;
                case 'B':
                    id = 2;
                    break;
            }
            if (id !== -1) {
                var node = math.parse(eq[1], scope);
                for (var i = 0; i < this.imageData.data.length; i += 4) {
                    scope.R = this.imageData.data[i];
                    scope.G = this.imageData.data[i + 1];
                    scope.B = this.imageData.data[i + 2];

                    // execute formula
                    data[i + id] = node.eval();
                    //console.log(eq[1]);
                }
            }
        }
        if (this.mode === "gray") {
            this.applyGrayScale(data);
        }

        imageData.data = data;
        ctx.putImageData(imageData, 0, 0);
    },

    // below code is from http://stackoverflow.com/questions/18480474/how-to-save-an-image-from-canvas
    downloadImage: function () {
        var lnk = document.createElement('a'), e;
        lnk.download = this.filename;
        lnk.href = this.canvas.toDataURL();
        if (document.createEvent) {
            e = document.createEvent("MouseEvents");
            e.initMouseEvent("click", true, true, window,
                             0, 0, 0, 0, 0, false, false, false,
                             false, 0, null);
            lnk.dispatchEvent(e);
        } else if (lnk.fireEvent)
            lnk.fireEvent("onclick");
    },
    // save imageData from context to our manipulator
    saveTemporary: function() {
        this.imageData = this.canvas.getContext('2d').getImageData(0, 0, this.canvas.width, this.canvas.height);
        //this.canvas.getContext('2d').drawImage(this.image, 0, 0, this.canvas.width, this.canvas.height);
        var data = this.canvas.toDataURL();
        $('#image').attr('src', data);
        this.setImage(data);
        this.rActive = true;
        this.gActive = true;
        this.bActive = true;
        this.mode = 'rgb';
    },
    applyGrayScale: function (data) {
        var gray = 0;
        // 3 canals active
        if (this.rActive && this.gActive && this.bActive) {
            for (var i = 0; i < data.length; i += 4) {
                var gray = 0.34 * data[i] + 0.5 * data[i + 1] + 0.16 * data[i + 2] ;
                data[i] = gray;
                data[i + 1] = gray;
                data[i + 2] = gray
            }
        }
            // 2 canals RG
        else if (this.rActive && this.gActive) {
            for (var i = 0; i < data.length; i += 4) {
                var gray = (data[i] + data[i + 1]) / 2;
                data[i] = gray;
                data[i + 1] = gray;
                data[i + 2] = gray;
            }
        }
            // 2 canals RB
        else if (this.rActive && this.bActive) {
            for (var i = 0; i < data.length; i += 4) {
                var gray = (data[i] + data[i + 2]) / 2;
                data[i] = gray;
                data[i + 1] = gray;
                data[i + 2] = gray;
            }
        }
            // 2 canals GB
        else if (this.gActive && this.bActive) {
            for (var i = 0; i < data.length; i += 4) {
                var gray = (data[i + 1] + data[i + 2]) / 2;
                data[i] = gray;
                data[i + 1] = gray;
                data[i + 2] = gray;
            }
        }
            // 1 canal R
        else if (this.rActive) {
            for (var i = 0; i < data.length; i += 4) {
                var gray = data[i];
                data[i] = gray;
                data[i + 1] = gray;
                data[i + 2] = gray;
            }
        }
            // 1 canal G
        else if (this.gActive) {
            for (var i = 0; i < data.length; i += 4) {
                var gray = data[i + 1];
                data[i] = gray;
                data[i + 1] = gray;
                data[i + 2] = gray;
            }
        }
            // 1 canal B
        else if (this.bActive) {
            for (var i = 0; i < data.length; i += 4) {
                var gray = data[i + 2];
                data[i] = gray;
                data[i + 1] = gray;
                data[i + 2] = gray;
            }
        }
            // 0 canals
        else {
            for (var i = 0; i < data.length; i += 4) {
                var gray = 0;
                data[i] = gray;
                data[i + 1] = gray;
                data[i + 2] = gray;
            }
        }
    }
});